# 模块作为命名空间使用

# 创建模块 MyMath
module MyMath
  # 常量
  PI = 3.1415926

  # 模块方法
  def self.circle_area(r)
    PI * r ** 2
  end

  # 嵌套类
  class Calculator
    # 实例方法
    def add(a, b)
      a + b
    end
  end
end

puts MyMath::PI                   # 访问常量 3.1415926
puts MyMath.circle_area(5)        # 调用模块方法 78.539815
calc = MyMath::Calculator.new     # 创建嵌套类实例
puts calc.add(3, 4)               # 输出: 7

puts "==========================================="

# 定义可混入模块

# 定义模块
module Swimmable
  # 定义方法
  def swim
    "#{self.class} can swim!"
  end
end

# 定义模块
module Flyable
  # 定义方法
  def fly
    "#{self.class} can fly!"
  end
end

# 混入到类中

# 定义类 Duck
class Duck
  # 混入模块
  include Swimmable
  include Flyable
end

# 定义类 Fish
class Fish
  # 混入模块
  include Swimmable
end

# 使用混入模块的类
duck = Duck.new
puts duck.swim  # 输出: Duck can swim!
puts duck.fly   # 输出: Duck can fly!

# 使用混入模块的类
fish = Fish.new
puts fish.swim  # 输出: Fish can swim!
# fish.fly      # 会报错，Fish没有fly方法

puts "==========================================="

# 作为工具方法库使用

# 定义模块 StringUtils
module StringUtils
  # 定义方法 random_string
  def self.random_string(length=8)
    chars = [*'a'..'z', *'A'..'Z', *'0'..'9']
    chars.sample(length).join
  end

  # 定义方法 truncate
  def self.truncate(str, length=20)
    str.length > length ? "#{str[0..length]}..." : str
  end
end

puts StringUtils.random_string(10)        # 随机字符串
puts StringUtils.truncate("这是一个很长的字符串需要截断") # 截断字符串

puts "==========================================="

# 模块扩展(extend)
module ClassMethods
  def class_method
    "This is a class method"
  end
end

# 将模块方法作为类方法添加
class MyClass
  extend ClassMethods
end

puts MyClass.class_method  # 输出: This is a class method

puts "==========================================="

# 模块被include/extend时的回调

module MyModule
  def self.included(base)
    puts "#{self} 被包含到 #{base} 中"
    base.extend ClassMethods
  end

  module ClassMethods
    def class_method
      "Added class method"
    end
  end

  def instance_method
    "Instance method"
  end
end

# 定义类 TestClass
class TestClass
  # 调用 include 方法，则会触发 base.extend ClassMethods
  include MyModule
end

puts TestClass.class_method  # 输出: Added class method
puts TestClass.new.instance_method # 输出: Instance method

puts "==========================================="

# 多个模块可以组合使用

# 定义模块 A
module A
  # 定义方法 a_method 返回 A
  def a_method; "A"; end
end

# 定义模块 B
module B
  # 定义方法 b_method 返回 B
  def b_method; "B"; end
end

# 定义模块 C，包含 A 和 B
module C
  include A
  include B

  # 定义方法 c_method 返回 A + B + C
  def c_method
    a_method + b_method + "C"
  end
end

# 定义类 D，包含 C
class D
  include C
end

# 输出结果
puts D.new.c_method  # 输出: ABC

puts "==========================================="

# 解决命名冲突
module M1
  def method
    "M1"
  end
end

module M2
  def method
    "M2"
  end
end

class MyClass
  include M1
  include M2

  def call_method
    method  # 调用最后被include的模块方法
  end
end

puts MyClass.new.call_method  # 输出: M2